#!/usr/bin/python
# -*- coding: UTF-8 -*-

import json
import random
import re
import string
import threading

import requests

from enums.sys_type_enum import SysTypeEnum
from utils.commit.oversea_regions import OVERSEA_REGIONS
from utils.commit.submit_tx import SubmitTypeEnum
from utils.commit.submit_wjx_v2 import QuestionareSpider
from utils.common.init_app import app
from utils.common.time_util import get_time_stamp13_now, get_utc_time_str_before_now_s, get_timestamp_before_now
from utils.ip_proxy.pinzan_ip_proxy import PinzanHttpProxy
from utils.submit_ua import UserAgentGenerate

session = requests.Session()


class QuestionareSpiderQualtrics(QuestionareSpider):
    def __init__(self, send_title_link, pz_obj, wo_topic_id, sleep_time, area):
        super().__init__(send_title_link, pz_obj, wo_topic_id, sleep_time, area)
        self.sessions = session
        # self.proxy_obj = proxy_obj
        self.pz_obj: PinzanHttpProxy = pz_obj
        self.title_link = send_title_link
        self.wo_topic_id = wo_topic_id
        self.headers = {}
        self.sleep_time = sleep_time or 20  # 问卷需要填写的时间,默认20秒
        self.area = area
        self.ua = UserAgentGenerate.random_phone_micro_messenger()  # 初始化实例默认获取一个ua
        self.can_get_7_code = True

    def get_url_and_params(self, submit_data):
        """
        获取url和参数
        :param submit_data:
        :return:
        """
        if submit_data is None:
            # submit_data为空则判定为初始页面
            return self.title_link, None, 0
        data_1_json = submit_data
        jfe_val = data_1_json['SM']['JFEDataCenter']
        link_sep_arr = self.title_link.split('jfe')
        # 如果链接包含问号？，则去掉问号及以后的部分（少数链接会有这种情况）
        if '?' in self.title_link:
            pure_link = self.title_link.split('?')[0]
            link_sep_arr = pure_link.split('jfe')
        url = link_sep_arr[0] + jfe_val + link_sep_arr[1] + '/next'
        rand = generate_random_number(9)
        tid = data_1_json['TransactionID']  # 3,5,7
        page_num = (int(tid) + 1) / 2
        timestamp = get_time_stamp13_now()
        send_param = f'rand={rand}&tid={tid}&t={timestamp}'
        return url, send_param, page_num

    def get_submit_result(self, submit_data, submit_type):
        """
        提交问卷
        :param submit_data: 需要提交数据
        :param submit_type:
        :return:
        """
        # 1. 构建提交参数
        cur_header = dict()
        cur_header['content-type'] = 'application/json; charset=utf-8'
        cur_header['user-agent'] = self.ua  # 模拟微信请求头
        url, send_param, page_num = self.get_url_and_params(submit_data)
        thread_id = threading.get_ident()
        app.logger.info(f'qual_thread_id:{thread_id}; url={url}')
        if 0 != page_num:
            app.logger.info(f'qual_thread_id:{thread_id}; -------------------开启提交(当前为第{page_num}页)-----------------')
            app.logger.info(f'qual_thread_id:{thread_id}; send_param-->{send_param}')
            app.logger.info(f'qual_thread_id:{thread_id}; submit_data={json.dumps(submit_data)}')
        # 2. 判断ip是否可用
        self.is_ip_available()  # 判断当前ip是否过期，如果过期重新获取一个ip并且立即发送请求
        # 3. 发送请求
        # app.logger.info(f'area：{self.area}')
        if self.area in OVERSEA_REGIONS:  # 海外发送请求
            # app.logger.info('发送到海外服务器')
            # 1, 获取海外的代理地址，2，发送到海外服务器
            upper_area = self.area.upper()
            p_url = 'http://cuveecui-' + upper_area + ':yydj8888@proxy.smartproxycn.com:1000'
            oversea_param_dict = dict()
            oversea_param_dict['request_headers'] = cur_header
            oversea_param_dict['proxy_url'] = p_url
            sys_oversea_url = 'http://8.137.54.97:7002/api/overseas/submit'
            oversea_header = dict()
            # oversea_header['content-type'] = 'application/json; charset=UTF-8'
            if submit_data is None:
                oversea_send_url = url

            else:
                oversea_send_url = url + '?' + send_param
                oversea_param_dict['submit_data'] = json.dumps(submit_data)
            oversea_param_dict['url'] = oversea_send_url
            oversea_response = requests.post(url=sys_oversea_url, headers=oversea_header, json=oversea_param_dict,
                                             timeout=10)
            if 200 == oversea_response.status_code:
                tmp_content = oversea_response.content.decode()  # oversea_response.text
                tmp_content_json = json.loads(tmp_content)
                pd = tmp_content_json['result']
            else:
                app.logger.error(f'qual_thread_id:{thread_id}; status_code={oversea_response.status_code}')
                raise Exception('发送海外数据失败')
        else:  # 默认国内直接发送
            if submit_data is None:  # 首页
                res = requests.get(url=url, headers=cur_header, timeout=30, proxies=self.pz_obj.proxies,
                                   allow_redirects=False)
            else:  # 下一页
                res = requests.post(url=url, params=send_param, json=submit_data, headers=cur_header, timeout=30,
                                    proxies=self.pz_obj.proxies, allow_redirects=False)
                app.logger.info(f'qual_thread_id:{thread_id}; response_data={res}')
            pd = res.content.decode()  # res.text
        return pd

    def submit(self, submit_data):
        """
        提交问卷
        :param submit_data: 需要提交数据
        :return:
        """
        pd = self.get_submit_result(submit_data, SubmitTypeEnum.WX)  # 默认微信提交
        if pd.startswith('10〒'):
            pass
        elif pd.startswith('5〒'):  # 5〒很抱歉，必须微信登录才能填写！
            # 默认就是微信提交，说明此时不应该再用微信提交，则转为使用手机提交
            self.ua = UserAgentGenerate.random_pc()  # 获取pd的ua
            pd = self.get_submit_result(submit_data, SubmitTypeEnum.PHONE)
        elif pd.startswith('7〒'):  # 需要智能验证
            pass
        else:
            pass
        return pd


def generate_random_number(n):
    """生成n位长度的随机数字串"""
    digits = string.digits
    return ''.join(random.choice(digits) for _ in range(n))


def convert_data_common(db_res_arr, db_title_arr, qr_key_list, qr_val_list, res):
    """作为convert_data_to_submit_data和 convert_data_to_submit_data_next_page的公用部分代码"""
    for index in range(len(qr_key_list)):
        i = db_title_arr[0]
        indexes = i['data_index']
        cur_type = i['sys_type']
        options = i['options']
        # app.logger.info(f'index={index}')
        cur_item = qr_val_list[index]
        if cur_type == SysTypeEnum.SINGLE.value:  # 单选题
            # 数据格式：{"Active":true,"Autofilled":false,"ChoiceOrder":["1","2","3"],"ChoiceOrderSetup":true,"ChoiceTextPosition":"Left","Choices":{"1":{"Display":"单选项1","Displayed":true,"Error":null,"ErrorMsg":null,"Exclusive":false,"ID":"1","InputHeight":null,"InputWidth":null,"PDPError":null,"PDPErrorMsg":null,"Password":false,"RecodeValue":"1","Selected":false,"Text":"","TextEntry":false,"TextEntryLength":null,"TextEntrySize":"Small","VariableName":"1"},"2":{"Display":"单选项2","Displayed":true,"Error":null,"ErrorMsg":null,"Exclusive":false,"ID":"2","InputHeight":null,"InputWidth":null,"PDPError":null,"PDPErrorMsg":null,"Password":false,"RecodeValue":"2","Selected":true,"Text":"","TextEntry":false,"TextEntryLength":null,"TextEntrySize":"Small","VariableName":"2"},"3":{"Display":"单选项3","Displayed":true,"Error":null,"ErrorMsg":null,"Exclusive":false,"ID":"3","InputHeight":null,"InputWidth":null,"PDPError":null,"PDPErrorMsg":null,"Password":false,"RecodeValue":"3","Selected":false,"Text":"","TextEntry":false,"TextEntryLength":null,"TextEntrySize":"Small","VariableName":"3"}},"CurrentMultiPageQuestionIndex":0,"Displayed":true,"ErrorMsg":null,"ErrorSeverity":null,"ExistingChoices":{},"Highlight":false,"ID":"QID1","IsAutoAuthFailure":false,"IsResponseSummary":false,"MobileFirst":false,"PDPError":null,"PDPErrorMsg":null,"PreValidation":{"Settings":{"ForceResponse":"ON","ForceResponseType":"ON","Type":"None"}},"ProcessedDisplayChoiceOrder":["1","2","3"],"QuestionText":"单选题","QuestionTypePluginProperties":null,"Selected":"2","Selector":"SAVR","SeparatorDisplayed":true,"SubSelector":"TX","TerminalAuthError":false,"Type":"MC","Valid":false}
            cur_value = str(db_res_arr.pop(0))  # str(db_res_arr[indexes[0]])
            if '-3' == cur_value:  # -3直接跳过这条数据
                continue
            for option in options:
                if str(option['value']) == cur_value:  # 所有数据转换为字符串进行比较
                    cur_item['Selected'] = cur_value  # 选项答案
                    cur_item['Choices'][cur_value]['Selected'] = True
                    break
        elif cur_type == SysTypeEnum.MULTIPLE.value:  # 多选题
            opt_counter = 0
            is_jump = False
            for option in options:
                db_value = str(db_res_arr.pop(0))  # db_res_arr[option['data_index']]
                opt_counter += 1
                if '-3' == db_value:  # -3直接跳过这条数据
                    is_jump = True
                    break
                if '1' != str(db_value):
                    continue
                cur_item['Choices'][str(opt_counter)]['Selected'] = True
            if is_jump:
                continue
        elif cur_type == SysTypeEnum.SINGLE_SELECT.value:  # 下拉单选题
            cur_value = str(db_res_arr.pop(0))  # str(db_res_arr[indexes[0]])
            if '-3' == cur_value:  # -3直接跳过这条数据
                continue
            for option in options:
                if str(option['value']) == cur_value:  # 所有数据转换为字符串进行比较
                    cur_item['Selected'] = cur_value  # 选项答案
                    cur_item['Choices'][cur_value]['Selected'] = True
                    break
        elif cur_type == SysTypeEnum.SCALE.value:  # 单选量表题
            selected_value = str(db_res_arr.pop(0))  # str(db_res_arr[indexes[0]])
            if '-3' == selected_value:  # -3直接跳过这条数据
                continue
            if "MC|NPS" == i['title_type']:
                selected_value = str(int(selected_value) - 1)
            cur_item['Choices'][str(selected_value)]['Selected'] = True
            cur_item['Selected'] = selected_value  # 选项答案
        elif cur_type == SysTypeEnum.TEXT.value:  # 填空题
            filled_value = str(db_res_arr.pop(0))  # str(db_res_arr[indexes[0]])
            if '-3' == filled_value:  # -3直接跳过这条数据
                continue
            cur_item['Value'] = filled_value  # 填空内容
        elif cur_type == SysTypeEnum.DATE.value:  # 日期题
            filled_value = str(db_res_arr.pop(0))  # str(db_res_arr[indexes[0]])
            if '-3' == filled_value:  # -3直接跳过这条数据
                continue
            cur_item['Value'] = filled_value
        elif cur_type == SysTypeEnum.MATRIX.value:  # 单选矩阵题
            children = i['children']
            row_counter = 0
            is_jump = False
            choice_list = cur_item['ChoiceOrder']
            for cur_child in children:
                options = cur_child['options']
                cur_value = str(db_res_arr.pop(0))  # str(db_res_arr[indexes[row_counter]])
                row_counter += 1
                if '-3' == cur_value:  # -3直接跳过这条数据
                    is_jump = True
                    break
                for option in options:
                    if str(option['value']) == cur_value:
                        cur_item['Choices'][choice_list[row_counter-1]]['Answers'][cur_value]['Selected'] = True
                        cur_item['Choices'][choice_list[row_counter-1]]['Selected'] = cur_value  # 选项答案
                        disp = cur_item['Choices'][choice_list[row_counter-1]]['Answers'][cur_value]['Display']
                        cur_item['Choices'][choice_list[row_counter-1]]['SelectedDisplay'] = disp
                        break
            if is_jump:
                continue
            cur_item['RedrawHeaderPoint'] = row_counter - 1
            cur_item['WhiteSpacePoint'] = 2
            cur_item['rowCount'] = row_counter
        elif cur_type == SysTypeEnum.CASCADE_DROPDOWN.value:  # 级联下拉题
            pass  # 暂无
        elif cur_type == SysTypeEnum.SINGLE_SLIDE.value:  # 单个滑动条
            cur_value = str(db_res_arr.pop(0))  # str(db_res_arr[indexes[0]])
            if '-3' == cur_value:  # -3直接跳过这条数据
                continue
            cur_item['Choices']['1']['Value'] = cur_value  # 滑动条选值
            cur_item['Choices']['1']['NASelected'] = False
            cur_item['Choices']['1']['Selected'] = True
            cur_item['Choices']['1']['ToolTipActive'] = False
        elif cur_type == SysTypeEnum.SLIDE.value or cur_type == SysTypeEnum.RATE.value:  # 矩阵滑动条或者比重题
            children = i['children']
            row_counter = 0
            is_jump = False
            choice_list = cur_item['ChoiceOrder']
            for cur_child in children:
                cur_value = str(db_res_arr.pop(0))  # str(db_res_arr[indexes[row_counter]])
                if '-3' == cur_value:  # -3直接跳过这条数据
                    is_jump = True
                    break
                row_counter += 1
                cur_item['Choices'][choice_list[row_counter-1]]['NASelected'] = False
                cur_item['Choices'][choice_list[row_counter-1]]['Selected'] = True
                cur_item['Choices'][choice_list[row_counter-1]]['ToolTipActive'] = False
                cur_item['Choices'][choice_list[row_counter-1]]['Selected'] = True
                cur_item['Choices'][choice_list[row_counter-1]]['Value'] = cur_value
            if is_jump:
                continue
        elif cur_type == SysTypeEnum.SORTED.value:  # 排序题
            opt_counter = 0
            is_jump = False
            for option in options:
                opt_counter += 1
                db_value = str(db_res_arr.pop(0))  # db_res_arr[option['data_index']]
                if '-3' == db_value:  # -3直接跳过这条数据
                    is_jump = True
                    break
                sort_no = db_value
                cur_item['Choices'][str(opt_counter)]['Selected'] = True
                cur_item['Choices'][str(opt_counter)]['Value'] = sort_no
            if is_jump:
                continue
        elif cur_type == SysTypeEnum.MULTIPLE_TEXT.value:  # 多项填空
            children = i['children']
            filling_counter = 0  # 填空项个数计数
            is_jump = False
            for cur_child in children:  # 每个child代表一个填空项
                filling_counter += 1
                db_value = str(db_res_arr.pop(0))  # str(db_res_arr[cur_child['data_index']])
                if '-3' == db_value:  # -3直接跳过这条数据
                    is_jump = True
                    break
                cur_item['Choices'][str(filling_counter)]['Text'] = db_value
            if is_jump:
                continue
        elif cur_type == SysTypeEnum.MULTIPLE_MATRIX.value:  # 矩阵多选
            children = i['children']
            row_counter = 0
            is_jump = False
            choice_list = cur_item['ChoiceOrder']
            answer_list = cur_item['AnswerOrder']
            for cur_child in children:  # 每个child代表一行
                row_counter += 1
                col_counter = 0
                options = cur_child['options']
                val_list = list()
                for option in options:
                    col_counter += 1
                    db_value = str(db_res_arr.pop(0))  # str(db_res_arr[option['data_index']])
                    if '-3' == db_value:  # -3直接跳过这条数据
                        is_jump = True
                        break
                    if '1' != db_value:
                        continue
                    answer_key = answer_list[col_counter - 1]
                    cur_item['Choices'][choice_list[row_counter-1]]['Answers'][answer_key]['Selected'] = True
                    val_list.append(answer_key)
                if is_jump:
                    break
                cur_item['Choices'][choice_list[row_counter-1]]['Selected'] = ','.join(val_list)
            if is_jump:
                continue
            cur_item['RedrawHeaderPoint'] = row_counter - 1
            cur_item['WhiteSpacePoint'] = 2
            cur_item['rowCount'] = row_counter
        elif cur_type == SysTypeEnum.MATRIX_TEXT.value:  # 矩阵填空
            children = i['children']
            row_counter = 0
            is_jump = False
            choice_list = cur_item['ChoiceOrder']
            answer_list = cur_item['AnswerOrder']
            for cur_child in children:  # 每个child代表一行
                row_counter += 1
                col_counter = 0
                options = cur_child['options']
                for option in options:
                    col_counter += 1
                    db_value = str(db_res_arr.pop(0))  # str(db_res_arr[option['data_index']])
                    if '-3' == db_value:  # -3直接跳过这条数据
                        is_jump = True
                        break
                    answer_key = answer_list[col_counter-1]
                    cur_item['Choices'][choice_list[row_counter-1]]['Answers'][answer_key]['Selected'] = True
                    cur_item['Choices'][choice_list[row_counter-1]]['Answers'][answer_key]['Value'] = db_value
                if is_jump:
                    break
                cur_item['Choices'][choice_list[row_counter-1]]['Selected'] = True
            if is_jump:
                continue
            cur_item['RedrawHeaderPoint'] = row_counter - 1
            cur_item['WhiteSpacePoint'] = 2
            cur_item['rowCount'] = row_counter
        else:  # 未知
            pass
        # 有些问卷没有下面两个而有些则有，目前发现有的话就每一道题都有，没有就每一道题都没有
        cur_item['IsResponseSummary'] = False
        cur_item['SeparatorDisplayed'] = True
        del db_title_arr[0]
    for idx in range(len(qr_key_list)):
        res['Questions'][qr_key_list[idx]] = qr_val_list[idx]
    # app.logger.info(f'res={json.dumps(res)}')


def is_desc_qst(qr_item):
    """
    判断是否是描述性题目
    :param qr_item: 原始QuestionRuntimes中的每一项
    :return:
    """
    # 常见描述性题目
    if "DB" == qr_item['Type'] or "Timing" == qr_item['Type'] or "Meta" == qr_item['Type']:
        return True
    # 另外还有无选项时的单选多选排序选择也视为占位题DESCRIPTION描述性题目
    elif "MC" == qr_item['Type']:
        if "SAVR" == qr_item['Selector'] or "SB" == qr_item['Selector'] or "SAHR" == qr_item['Selector']:  # 单选
            if 0 == len(qr_item['ChoiceOrder']):
                return True
        elif "MAVR" == qr_item['Selector'] or "MACOL" == qr_item['Selector']:  # 多选
            if 0 == len(qr_item['ChoiceOrder']):
                return True
    elif "RO" == qr_item['Type']:  # 排序
        if 0 == len(qr_item['ChoiceOrder']):
            return True
    return False


def convert_data_to_submit_data(db_title_arr, db_res_arr, qo, sleep_time):
    """
    将数据库中的数据转换为需要提交的结果数据
    :param db_title_arr: 题目与数据库结果的映射关系数组
    :param db_res_arr: 需要提交的答案数组
    :param qo: QuestionareSpiderQualtrics对象
    :param sleep_time: 睡眠时间（即一张问卷的总答题时长）
    :return:
    """
    # 获取初始数据
    # link = 'https://qfreeaccountssjc1.az1.qualtrics.com/jfe/form/SV_bsaB75CpFDfWwV8'
    # header = {'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
    #           'Chrome/95.0.4638.69 Safari/537.36', }
    # response_1 = requests.get(link, allow_redirects=False, headers=header, timeout=10, proxies=proxy_obj.proxies)
    # content = response_1.text  # response_1.content.decode('utf-8')
    content = qo.submit(None)
    pattern = r'.*?\((\{"FormSessionID".*?\})\)'
    find_result = re.findall(pattern, content)
    if len(find_result) < 1:
        raise Exception("未找到数据")
    data_1 = find_result[0]
    app.logger.debug(f"qual_thread_id:{threading.get_ident()}; Initial_questions:{data_1}")
    # 构造下一页数据并提交
    # data_1 = '{"FormSessionID":"FS_4UrPHWY3ErEqpGx","QuestionIDs":["QID2","QID3"],"QuestionDefinitions":......}'
    data_1_json = json.loads(data_1)
    sm = data_1_json['SM']
    sm['FlashVersion'] = -1
    sm['JavaSupport'] = 0
    sm['Resolution'] = "1920x1080"
    sm['StartDate'] = get_utc_time_str_before_now_s(sleep_time)  # "2024-11-20 09:07:20"  # 北京时间-8小时（即同一时刻的UTC时间）
    sm['StartDateRaw'] = get_timestamp_before_now(sleep_time)  # 1732093640119  # 北京时间
    res = {
        "ED": data_1_json['ED'],
        "EDMETA": {},
        "FormRuntime": data_1_json['FormRuntime'],
        "FormSessionID": data_1_json['FormSessionID'],
        "PageAnalytics": {},
        "ProgressState": [],
        "Questions": {},
        "RuntimePayload": data_1_json['RuntimePayload'],
        "SM": sm,
        "TransactionID": data_1_json['TransactionID']
    }
    qr = data_1_json['QuestionRuntimes']
    qr_val_list = list()
    qr_key_list = list()
    for key, value in qr.items():
        # 过滤掉占位题DESCRIPTION描述性题目
        if is_desc_qst(qr[key]):
            continue
        qr_key_list.append(key)
        qr_val_list.append(value)
    convert_data_common(db_res_arr, db_title_arr, qr_key_list, qr_val_list, res)
    return res


def convert_data_to_submit_data_next_page(db_title_arr, db_res_arr, resp_str):
    """
    将数据库中的数据转换为需要提交的结果数据(下一页)
    :param db_title_arr: 题目与数据库结果的映射关系数组
    :param db_res_arr: 需要提交的答案数组
    :param resp_str: 上一个的请求返回的响应结果
    :return:
    """
    # 获取初始数据
    # link = 'https://qfreeaccountssjc1.az1.qualtrics.com/jfe4/form/SV_5tCmoTkUaZwjKCy/next'
    header = {'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
                            'Chrome/95.0.4638.69 Safari/537.36', }
    # resp_str = '{"FormSessionID":"FS_4PUDvWdhc5SXBCs","QuestionIDs":["QID3","QID4"],"QuestionDefinitions":......}'
    resp_json = json.loads(resp_str)
    sm = resp_json['SM']
    sm['FlashVersion'] = -1
    sm['JavaSupport'] = 0
    sm['Resolution'] = "1920x1080"
    res = {
        "ED": resp_json['ED'],
        "EDMETA": {},
        "FormRuntime": resp_json['FormRuntime'],
        "FormSessionID": resp_json['FormSessionID'],
        "PageAnalytics": {},
        "ProgressState": [],
        "Questions": {},
        "RuntimePayload": resp_json['RuntimePayload'],
        "SM": sm,
        "TransactionID": resp_json['TransactionID']
    }
    qr = resp_json['QuestionRuntimes']
    qr_val_list = list()
    qr_key_list = list()
    for key, value in qr.items():
        # 过滤掉占位题DESCRIPTION描述性题目
        if is_desc_qst(qr[key]):
            continue
        qr_key_list.append(key)
        qr_val_list.append(value)
    convert_data_common(db_res_arr, db_title_arr, qr_key_list, qr_val_list, res)
    return res


def get_proxy_obj(proxy_region):
    """ 获取品赞代理（一个问卷调用一次，无论该问卷有多少页的请求） """
    virtual_proxy_area = proxy_region
    if proxy_region in OVERSEA_REGIONS:  # 海外发送请求，默认先使用国内的'全国'请求地址，最后发送的时候改为获取海外的ip
        virtual_proxy_area = 'all'
    pz_obj = PinzanHttpProxy(virtual_proxy_area)
    pz_obj.get_proxy()
    return pz_obj


def get_qsq(send_title_link, wo_topic_id, sleep_time, proxy_region):
    """ 获取QuestionareSpiderQualtrics对象 """
    proxy_obj = get_proxy_obj(proxy_region)
    qo = QuestionareSpiderQualtrics(send_title_link=send_title_link, pz_obj=proxy_obj,
                                    wo_topic_id=wo_topic_id,
                                    sleep_time=sleep_time, area=proxy_region)
    return qo


def do_submit(submit_data, db_title_arr, db_res_arr, qo):
    # app.logger.info(f'do_submit提交数据，wo_topic_id:{wo_topic_id}')
    # 创建问卷对象, 发送请求
    resp = qo.submit(submit_data)  # 提交
    resp_json = json.loads(resp)
    prog_percent = resp_json['ProgressPercent']
    thread_id = threading.get_ident()
    app.logger.info(f"qual_thread_id:{thread_id}; response_Messages:{resp_json['Messages']}")
    last_prog_percent = -1  # 用于防止未答题就提交导致下面循环不停止
    while 100 != prog_percent:
        if last_prog_percent == prog_percent:  # 如果和上次的进度百分比相同，说明没有答题，则跳出循环
            app.logger.error(f'qual_thread_id:{thread_id}; 存在未答题，当前进度百分比：{prog_percent}')
            raise Exception('存在未答题，异常退出！')
        else:
            last_prog_percent = prog_percent
        # 获取下一页的题目解析结果
        submit_data = convert_data_to_submit_data_next_page(db_title_arr, db_res_arr, resp)
        resp = qo.submit(submit_data)
        resp_json = json.loads(resp)
        prog_percent = resp_json['ProgressPercent']
        app.logger.info(f'qual_thread_id:{thread_id}; response_text-->' + json.dumps(resp_json['Messages']))
    # app.logger.info(submit_data)
    return resp, qo.pz_obj.host_port_city


# Press the green button in the gutter to run the script.
if __name__ == '__main__':
    pass
